/*
 * URT.cpp
 *
 *  Created on: May 21, 2011
 *      Author: ulas
 */

#include "URT.h"

URT::URT(U8 nodeId) : CLProtocol(nodeId)
{
	vCL = new vCLURT();
	DBG("URT Initiating, NODE_ID: %d\n", NODE_ID);
}

STATUS URT::gUpdate(const U8 *msg, const U16 messageLength)
{
	U32 i;
	TimeInternal curTime, t;
	URT_MESSAGE_PARAMETER_TYPE par;
	URT_COMMUNICATION_REQUEST_PQ_TYPE* comReqPtr;
	par.totalNumberOfRequests = 0;
	t.seconds = 0;
	t.nanoseconds = 0;

	if(messageLength > 0) {
		par.totalNumberOfRequests  = msg[0];

		for(i = 0; i < par.totalNumberOfRequests; i++)	{
			par.comRequests[i] = *((URT_COMMUNICATION_REQUEST_TYPE* )&msg[ 1 + i*sizeof(URT_COMMUNICATION_REQUEST_TYPE)]);
		}
	}

	if ( (comReqPtr = (URT_COMMUNICATION_REQUEST_PQ_TYPE*)vCL->popNodeFromPQ()) == NULL)
	{
		PERROR("!!PQ is empty terminating URT!! \n");
		return ERROR;
	}

	getTime(&curTime);
	/*if no message is received (m.par = 0) even though the current slot is reserved as RT*/
	if( par.totalNumberOfRequests == 0 || messageLength == 0 )
	{
		DBG("URT.cpp|| NOT received RT message in correct slot re-enter PQ\n");
		/*re-enter the PQ with increased times*/
		t.nanoseconds = (comReqPtr->initialeT)*1000000;
		comReqPtr->eT = addTime(&curTime, &t);
		t.nanoseconds = (comReqPtr->initialdT)*1000000;
		comReqPtr->dT = addTime(&curTime, &t);
		vCL->insertNodeIntoPQ(comReqPtr);
	}
	else /*received RT message in RT slot*/
	{
		/*free the popped communication request*/
		free(comReqPtr);

		DBG("URT.cpp|| received RT message in correct slot\n");
		for(i = 0; i < par.totalNumberOfRequests; i++ )
		{
			/*!!!free edilmesi gerek!!!*/
			if ((comReqPtr =  (URT_COMMUNICATION_REQUEST_PQ_TYPE*)malloc(sizeof(URT_COMMUNICATION_REQUEST_PQ_TYPE)))== NULL) {
				PERROR("URT.cpp|| cannot allocate memory for comReq\n");
				return ERROR;
			}

			//memcpy(comReqPtr, &(par->comRequests[i]) , sizeof(URT_MESSAGE_PARAMETER_TYPE) );
			/*add the current time before adding m.par(s) to the PQ*/
			comReqPtr->ch = par.comRequests[i].ch;
			comReqPtr->nodeId = par.comRequests[i].nodeId;
			comReqPtr->initialeT = par.comRequests[i].eT;
			t.nanoseconds = (par.comRequests[i].eT)*1000000;
			comReqPtr->eT  = addTime( &curTime, &t);
			comReqPtr->initialdT = par.comRequests[i].dT;
			t.nanoseconds = (par.comRequests[i].dT)*1000000;
			comReqPtr->dT  = addTime( &curTime, &t);

			vCL->insertNodeIntoPQ(comReqPtr); // insertNodePQ(vCL->PQ, comReqPtr );
		}
	}

	return OK;
}

STATUS URT::gRealTime(SLOT_TYPE* RTCL)
{
	(*RTCL) = NON_REAL_TIME_SLOT;
	TimeInternal curTime;

	URT_COMMUNICATION_REQUEST_PQ_TYPE* topReq =  (URT_COMMUNICATION_REQUEST_PQ_TYPE*)vCL->peekNodeFromPQ();

	if( topReq == NULL ) {
		PERROR("!!gRealTime || PQ IS EMPTY!!");
		exit(EXIT_FAILURE);
	}
	getTime(&curTime);
	if( greaterThan( &curTime, &(topReq->eT) ) )
	{
		(*RTCL) = REAL_TIME_SLOT;
	}

	return OK;
}

STATUS URT::gMySlot(myCL_TYPE* myCL)
{
	myCL->mySlot = FALSE;
	myCL->ch = 0;

	URT_COMMUNICATION_REQUEST_PQ_TYPE* topReq =  (URT_COMMUNICATION_REQUEST_PQ_TYPE*)vCL->peekNodeFromPQ();

	if( topReq == NULL ) {
		PERROR("!!gMySlot || PQ IS EMPTY!!");
		exit(EXIT_FAILURE);
	}

	if(topReq->nodeId == NODE_ID) {
		myCL->mySlot = TRUE;
		myCL->ch = topReq->ch;
	}
	return OK;

}

U16 URT::prepareCLHeader(U8* msg, void* parPtr) {
	/*copy message parameters into the buffer that will be sent to IL  */
	U32 i;
	U16 CLHeaderLength = 0;
	URT_MESSAGE_PARAMETER_TYPE* par = (URT_MESSAGE_PARAMETER_TYPE*)parPtr;
	msg[0] = par->totalNumberOfRequests;

	for( i = 0; i < par->totalNumberOfRequests; i++) {
		*((URT_COMMUNICATION_REQUEST_TYPE* )&msg[1 + i*sizeof(URT_COMMUNICATION_REQUEST_TYPE)]) = par->comRequests[i];
		//memcpy( &msg[ 1 + i*sizeof(URT_COMMUNICATION_REQUEST_TYPE) ], &(parPtr->comRequests[i]), sizeof(URT_COMMUNICATION_REQUEST_TYPE));
	}

	CLHeaderLength = 1 + i*sizeof(URT_COMMUNICATION_REQUEST_TYPE);  //+2 byte payloadLength

	return CLHeaderLength;

}

U8 URT::getCLHeaderLength(U8* msg)
{
	return 1 + (*msg)*sizeof(URT_COMMUNICATION_REQUEST_TYPE);  //exclude 2 byte payloadLength
}

/*this function is required for DART and not for URT*/
void URT::updateCountForDART()
{

}

URT_COMMUNICATION_REQUEST_PQ_TYPE* URT::getAvailableRequest()
{
	U8 i;
	U8 j;
	URT_COMMUNICATION_REQUEST_PQ_TYPE* URTComReqPtr[URT_PRIORITY_QUEUE_SIZE];
	URT_COMMUNICATION_REQUEST_PQ_TYPE* avaliableReqPtr = NULL;
	TimeInternal curTime;
	getTime(&curTime);
	i = 0;
	while( (URTComReqPtr[i] = (URT_COMMUNICATION_REQUEST_PQ_TYPE*)vCL->popNodeFromPQ()) != NULL)
	{
		if( greaterThan( &curTime, &(URTComReqPtr[i]->eT) ) )
		{
			avaliableReqPtr = URTComReqPtr[i];
			i = i + 1;
			break;
		}
		i = i + 1;

	}
	if( i == 0)
	{
		PERROR("!!gRealTime || PQ IS EMPTY!!");
		exit(EXIT_FAILURE);
	}

	for(j=0; j < i; j++ )
	{
		vCL->insertNodeIntoPQ(URTComReqPtr[j]);
	}
	return avaliableReqPtr;
}

URT::~URT()
{
	delete vCL;
}
